import { Injectable } from '@nestjs/common'
import { PagerDto } from "@dto/public.dto";
import { HttpPageTemplate, HttpResTemplate, HttpResult } from "@libs/http.result";
import { Express } from "express";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, getConnection } from "typeorm";
import { FileBusinessEntity, FileEntity } from "@entities/file.entity";
import { BusinessException, ParamsException, ServerException } from "@exceptions";
import * as path from 'path'
import { format } from "@utils/date";
import { calcFileMD5 } from "@utils/file";
import { CatchError } from "@decorators/cache-error.decorator";
import { FileFilingDTO } from "@dto/file.dto";
import { SnowflakeId } from "@libs/snowflake.id";

@Injectable()
export class FileService {
    constructor(
        @InjectRepository(FileEntity)
        private readonly fileRepository: Repository<FileEntity>,
        @InjectRepository(FileBusinessEntity)
        private readonly fileBusinessRepository: Repository<FileBusinessEntity>
    ) {
    }
    /**
     * 获取文件列表
     * @param params
     */
    async getFileList(params: PagerDto): Promise<HttpPageTemplate> {
        return HttpResult.pageData({
            total: 10,
            list: []
        })
    }

    /**
     * 根据业务id获取文件列表
     */
    async getFileListByBizId(bizId: number): Promise<HttpResTemplate> {
        const builder = getConnection().createQueryBuilder(FileBusinessEntity, 'fb')
        const fileList = await builder.leftJoinAndSelect(FileEntity, 'f', 'f.id=fb.file_id')
                .where(`f.is_delete=0 AND fb.biz_id=${bizId}`)
                .getMany()
        console.log(fileList)
        return HttpResult.success(fileList)
    }

    /**
     * 文件上传
     */
    @CatchError('文件上传')
    async updateFile(file: Express.Multer.File): Promise<HttpResTemplate> {
        const newFile: FileEntity = this.fileRepository.create({
            id: file['fileId'],
            suffix: file['suffix'],
            size: file.size,
            path: file['savePath'].replace(/\\/g, '/'), // 转换正反斜线，转换结果如："public/uploads/image/2020-04-08/123456789.jpg"
            originName: file.originalname,
            name: file.filename,
            createBy: 'admin',
            createTime: format(new Date())
        })
        const fileMD5: string = await calcFileMD5(newFile.path)
        if (!fileMD5) {
            throw new BusinessException('文件生成HASH错误')
        }
        newFile.signHash = fileMD5
        const saveRes = await this.fileRepository.save(newFile)
        return HttpResult.success(saveRes)
    }

    /**
     * 下载文件
     * @param fileId
     */
    @CatchError('下载文件')
    async download(fileId: number): Promise<FileEntity> {
        if (!fileId) {
            throw new ParamsException('参数有误')
        }
        const file = await this.fileRepository.findOne({where: {id: fileId}})
        if (!file) {
            throw new BusinessException('文件不存在')
        }
        const filePath = path.join(file.path)
        const fileHash = await calcFileMD5(filePath) // 计算服务器中文件的HASH值
        if (!fileHash || fileHash !== file.signHash) {
            throw new ServerException(new Error(`文件HASH解析异常`))
        }
        return file
    }

    /**
     * 文件落盘
     * @param data
     */
    @CatchError('文件落盘')
    async filing(data: FileFilingDTO) {
        console.log(data.id)
        console.log(data.files)
        return HttpResult.success()
    }

    @CatchError('文件绑定业务并落盘')
    async bindBizAndFiling(data: FileFilingDTO) {
        const { id, files } = data
        const values: Array<FileBusinessEntity> = files.map(fId => {
            return {
                id: SnowflakeId.generate(),
                bizId: id,
                fileId: fId,
                remark: ''
            }
        })

        // 绑定业务
        const res = await this.fileBusinessRepository
            .createQueryBuilder()
            .insert()
            .into(FileBusinessEntity)
            .values(values)
            .execute()
        if (res.identifiers.length === 0) {
            throw new BusinessException('文件绑定、落盘失败')
        }
        return HttpResult.success()
    }

    /**
     * 删除文件
     * @param fileId
     */
    deleteFile(fileId: number) {

    }

    @CatchError('文件绑定业务并落盘')
    async batchDeleteFile() {

    }
}
